package dream

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"sync"
)

type IRequest = *http.Request

type IResponse interface {
	http.ResponseWriter
	WriteJson(map[string]interface{}) (int, error)
	WriteFmt(a ...interface{}) (int, error)
	WriteJsonArr(a ...map[string]interface{}) (int, error)
}

type sResponse struct {
	w http.ResponseWriter
}

func (p *sResponse) WriteJson(j map[string]interface{}) (int, error) {
	Logf("###返回###：%+v", j)
	b, err := json.Marshal(j)
	if err != nil {
		return 0, err
	}
	return p.w.Write(b)
}
func (p *sResponse) WriteJsonArr(j ...map[string]interface{}) (int, error) {
	var id = 0
	var err error = nil
	id, err = p.w.Write([]byte("["))
	if err != nil {
		return id, err
	}
	zhui := false
	for _, val := range j {
		if zhui {
			id, err = p.w.Write([]byte(","))
			if err != nil {
				return id, err
			}
		}
		id, err = p.WriteJson(val)
		if err != nil {
			return id, err
		}
		zhui = true
	}
	id, err = p.w.Write([]byte("]"))
	if err != nil {
		return id, err
	}
	return id, err
}
func (p *sResponse) WriteFmt(a ...interface{}) (int, error) {
	sss := fmt.Sprint(a...)
	return p.w.Write([]byte(sss))
}

func (p *sResponse) Header() http.Header {
	return p.w.Header()
}
func (p *sResponse) Write(b []byte) (int, error) {
	return p.w.Write(b)
}
func (p *sResponse) WriteHeader(statusCode int) {
	p.w.WriteHeader(statusCode)
}

type IHttpInterface interface {
	OnHttpRequest(r IRequest, file string, w IResponse)
}

type IHttpHandler interface {
	OnHttpRequest(r IRequest, w IResponse)
}

type sHandler struct {
	i IHttpHandler
}

func (p *sHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	defer func() { CrashSnap(recover()) }()
	p.i.OnHttpRequest(r, &sResponse{w: w})
}

var mu sync.RWMutex

func init() {
	mu = sync.RWMutex{}
}

type HttpFunc func(r IRequest, w IResponse)

func (f HttpFunc) OnHttpRequest(r IRequest, w IResponse) {
	f(r, w)
}

type HttpMux struct {
	mux *http.ServeMux
}

func (p *HttpMux) Handle(pattern string, handler IHttpHandler) {
	p.mux.Handle(pattern, &sHandler{i: handler})
}
func (p *HttpMux) HandleFunc(pattern string, handler func(IRequest, IResponse)) {
	p.mux.Handle(pattern, &sHandler{i: HttpFunc(handler)})
}

type IHttpServer interface {
	IRun
	IStop
}
type sHttpServer struct {
	svr    *http.Server
	lock   *sync.Mutex
	cbHttp IHttpInterface
	cbConn INewConnInterface
	cbIf   IClientInterface
	cbReg  IRegisterInterface
}

func (p *sHttpServer) Stop() {
	p.svr.Shutdown(context.Background())
}
func NewHttpMux() *HttpMux {
	return &HttpMux{
		mux: http.NewServeMux(),
	}
}
func (p *sHttpServer) Run(wg *sync.WaitGroup) {
	if wg != nil {
		wg.Add(1)
	}
	go func() {
		defer func() { CrashSnap(recover()) }()
		txt := "HttpServing"
		Logi(LOG_KERL, txt, " ", p.svr.Addr, " ...")
		err := p.svr.ListenAndServe()
		Logi(LOG_KERL, " ...", txt, " ", p.svr.Addr, " exit(", err, ")")
		if wg != nil {
			wg.Done()
		}
	}()
}

func ServeHttpAll(addr string, handler *HttpMux, cbConn INewConnInterface, cbIf IClientInterface, cbReg IRegisterInterface /*cbXY IXYInterface,, cbClose IConnCloseInterface*/) IHttpServer {
	AssertImposible(handler == nil && cbConn == nil && cbIf == nil, "ServeHttp::handler nil")

	var mux *http.ServeMux

	ps := &http.Server{
		Addr:    addr,
		Handler: mux,
	}
	p := &sHttpServer{
		svr:    ps,
		lock:   &sync.Mutex{},
		cbConn: cbConn,
		cbIf:   cbIf,
		cbReg:  cbReg,
		//cbXY:      cbXY,
		//cbClose: cbClose,
	}
	return p
}

func ServeHttp(addr string, handler *HttpMux) IHttpServer {
	return ServeHttpAll(addr, handler, nil, nil, nil)
}
